package net.jonbuck.tassoo.ui.view.page;

import java.util.Vector;

import net.jonbuck.tassoo.eventmanager.EventManager;
import net.jonbuck.tassoo.eventmanager.EventManagerImpl;
import net.jonbuck.tassoo.eventmanager.events.TaskCommentPreferencesUpdatedEvent;
import net.jonbuck.tassoo.model.Comment;
import net.jonbuck.tassoo.model.Task;
import net.jonbuck.tassoo.persistence.dao.TassooDao;
import net.jonbuck.tassoo.persistence.dao.TassooDaoImpl;
import net.jonbuck.tassoo.ui.nl.Messages;
import net.jonbuck.tassoo.ui.preference.CommentsPreferencePage;
import net.jonbuck.tassoo.ui.util.CommonImages;

import org.apache.commons.lang.StringUtils;
import org.apache.regexp.RE;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.LineStyleEvent;
import org.eclipse.swt.custom.LineStyleListener;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.wb.swt.SWTResourceManager;
import org.osgi.service.prefs.Preferences;

/**
 * 
 * 
 * @since 1.0.0
 */
public class TaskCommentsTab extends Composite {

	/** ... TODO Javadoc ... */
	private IAction addCommentAction = new Action(Messages.taskcommentsection_action_addcomment_text) {

		public ImageDescriptor getDisabledImageDescriptor() {
			return CommonImages.PLUS_DISABLED;
		}

		public ImageDescriptor getImageDescriptor() {
			return CommonImages.PLUS;
		}

		public void run() {
			addComment();
		}
	};

	/** ... TODO Javadoc ... */
	private Composite bodyComposite;

	/** ... TODO Javadoc ... */
	private IAction cancelCommentAction = new Action(Messages.taskcommentsection_action_cancelcomment_text) {

		public ImageDescriptor getDisabledImageDescriptor() {
			return CommonImages.CROSS_DISABLED;
		}

		public ImageDescriptor getImageDescriptor() {
			return CommonImages.CROSS;
		}

		public void run() {
			cancelComment();
		}
	};

	/** ... TODO Javadoc ... */
	private StyledText commentsTable;

	/** ... TODO Javadoc ... */
	private EventManager eventManager = EventManagerImpl.getInstance();

	/** ... TODO Javadoc ... */
	private Form commentsForm;

	/** ... TODO Javadoc ... */
	private GridData gd_bodyComposite;

	/** ... TODO Javadoc ... */
	private GridData gd_txtComment;

	/** ... TODO Javadoc ... */
	private int position;

	/** ... TODO Javadoc ... */
	private IPreferencesService preferenceService;

	/** ... TODO Javadoc ... */
	private IAction saveCommentAction = new Action(Messages.taskcommentsection_action_savecomment_text) {

		public ImageDescriptor getDisabledImageDescriptor() {
			return CommonImages.CHECK_DISABLED;
		}

		public ImageDescriptor getImageDescriptor() {
			return CommonImages.CHECK;
		}

		public void run() {
			saveComment();
		}
	};

	/** ... TODO Javadoc ... */
	private Task task;

	/** ... TODO Javadoc ... */
	private TassooDao tassooDao = TassooDaoImpl.getInstance();

	/** ... TODO Javadoc ... */
	private Preferences tassooNode;

	/** ... TODO Javadoc ... */
	private Text txtComment;

	/**
	 * 
	 * @param parent
	 * @param form
	 * @param position
	 */
	public TaskCommentsTab(Composite parent, Form form, int position) {
		super(parent, SWT.NONE);
		this.commentsForm = form;
		this.position = position;
		init();
	}

	/**
	 * 
	 */
	protected void addComment() {
		gd_txtComment.exclude = false;
		txtComment.setVisible(true);
		txtComment.setText(Messages.taskcommentsection_default_comment_text);
		txtComment.setSelection(0, Messages.taskcommentsection_default_comment_text.length());
		bodyComposite.layout();
		txtComment.forceFocus();
		addCommentAction.setEnabled(false);
		cancelCommentAction.setEnabled(true);
		saveCommentAction.setEnabled(true);
	}

	/**
	 * <p>
	 * <b>Cancel the entry of a comment by closing the field and resetting the
	 * buttons at the bottom of the section.</b>
	 * </p>
	 */
	protected void cancelComment() {
		hideCommentField();
		addCommentAction.setEnabled(true);
		cancelCommentAction.setEnabled(false);
		saveCommentAction.setEnabled(false);
	}

	/**
	 * <p>
	 * <b>Creates the contents of comment by generating an appropriate
	 * string.</b>
	 * </p>
	 * 
	 * @param sb
	 *            the buffer to add the comment content to.
	 * @param i
	 *            the current number of the attachment.
	 */
	private void createCommentDetail(StringBuilder sb, int i) {
		Comment comment = task.getComment().get(i);
		sb.append(i + 1);
		sb.append(". ");
		sb.append(comment.getDate());
		sb.append('\n');
		sb.append(comment.getText());
		if (i >= 0) {
			sb.append('\n');
			sb.append('\n');
		}
	}

	/**
	 * 
	 * @param parent
	 */
	private void createControl(Composite parent) {
		bodyComposite = new Composite(parent, SWT.NONE);
		bodyComposite.setLayout(new GridLayout());
		gd_bodyComposite = new GridData(SWT.FILL, SWT.FILL, true, true);
		bodyComposite.setLayoutData(gd_bodyComposite);

		// Comment Field
		txtComment = new Text(bodyComposite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.H_SCROLL);
		gd_txtComment = new GridData(SWT.FILL, SWT.CENTER, true, false);
		gd_txtComment.heightHint = 40;
		gd_txtComment.exclude = true;
		txtComment.setLayoutData(gd_txtComment);
		txtComment.setVisible(false);

		// Comments Table
		commentsTable = new StyledText(bodyComposite, SWT.BORDER | SWT.READ_ONLY | SWT.V_SCROLL);
		commentsTable.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));
		commentsTable.addLineStyleListener(new LineStyleListener() {

			Color dateLine = SWTResourceManager.getColor(SWT.COLOR_DARK_GRAY);

			// Check for date line.
			RE r = new RE("^[0-9]{1,2}\\. [0-9]{1,2} [A-Za-z]{3} [0-9]{4}\\, [0-9]{2}:[0-9]{2}$");

			public void lineGetStyle(LineStyleEvent event) {
				Vector<StyleRange> styles = new Vector<StyleRange>();

				String line = event.lineText;
				if (r.match(line)) {
					StyleRange style = new StyleRange(event.lineOffset, event.lineText.length(), dateLine, null);
					styles.add(style);
				} else {

				}

				event.styles = new StyleRange[styles.size()];
				styles.copyInto(event.styles);
			}
		});
	}

	/**
	 * <p>
	 * <b>Hides the comment field and resets the comment buttons at the bottom
	 * of the page.</b>
	 * </p>
	 */
	private void hideCommentField() {
		txtComment.setText(StringUtils.EMPTY);
		gd_txtComment.exclude = true;
		txtComment.setVisible(false);
		bodyComposite.layout();
	}

	/**
	 * 
	 * 
	 */
	private void init() {
		CTabFolder parentFolder = (CTabFolder) this.getParent();
		parentFolder.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				CTabFolder folder = (CTabFolder) e.widget;
				if (folder.getSelectionIndex() == position) {
					FormToolkit toolkit = new FormToolkit(getDisplay());
					commentsForm.getToolBarManager().removeAll();

					cancelCommentAction.setEnabled(false);
					saveCommentAction.setEnabled(false);
										
					commentsForm.getToolBarManager().add(addCommentAction);
					commentsForm.getToolBarManager().add(saveCommentAction);
					commentsForm.getToolBarManager().add(cancelCommentAction);

					commentsForm.getToolBarManager().update(true);
					
					toolkit.decorateFormHeading(commentsForm);
					toolkit.dispose();					
				}
			}
		});

		GridLayout gl = new GridLayout();
		gl.horizontalSpacing = 0;
		gl.verticalSpacing = 0;
		gl.marginWidth = 0;
		gl.marginHeight = 0;
		setLayout(gl);

		createControl(this);

		preferenceService = Platform.getPreferencesService();
		tassooNode = preferenceService.getRootNode().node(ConfigurationScope.SCOPE).node("net.jonbuck.tassoo");
		eventManager.addListener(TaskCommentPreferencesUpdatedEvent.class, this);
	}

	/**
	 * <p>
	 * <b>Populates the comments field with the data held in the currently
	 * selected task.</b>
	 * </p>
	 */
	private void populateCommentsTable() {
		StringBuilder sb = new StringBuilder();
		int totalCount = task.getComment().size();
		if (tassooNode.getBoolean(CommentsPreferencePage.NEWER_COMMENTS_FIRST, true)) {
			for (int i = totalCount - 1; i >= 0; i--) {
				createCommentDetail(sb, i);
			}
		} else {
			for (int i = 0; i < totalCount; i++) {
				createCommentDetail(sb, i);
			}
		}
		commentsTable.setText(sb.toString());
	}

	/**
	 * <p>
	 * <b>Saves the text entered in the comment field into a task comment and
	 * then closes the comment field whilst updating the comments table.</b>
	 * </p>
	 */
	protected void saveComment() {
		if (StringUtils.equals(Messages.taskcommentsection_default_comment_text, txtComment.getText())) {
			return;
		}
		tassooDao.createComment(task, txtComment.getText());
		hideCommentField();
		populateCommentsTable();
		addCommentAction.setEnabled(true);
		cancelCommentAction.setEnabled(false);
		saveCommentAction.setEnabled(false);
	}

	/**
	 * 
	 */
	public void setInput(Task task) {
		this.task = task;
		populateCommentsTable();
	}
	
}
